(*
  Copyright (c) 2009 Barry Schwartz

  Permission is hereby granted, free of charge, to any person
  obtaining a copy of this software and associated documentation
  files (the "Software"), to deal in the Software without
  restriction, including without limitation the rights to use,
  copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the
  Software is furnished to do so, subject to the following
  conditions:

  The above copyright notice and this permission notice shall be
  included in all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  OTHER DEALINGS IN THE SOFTWARE.
*)

open XNum
open UTypes
open Dim
open Substitute
open GlyphMetric
open FontMetric
open Box
module UniText = UniTools.UniText

(*?????????????????????????????????????????????????????????????????????????????????????????????????????????? *)
(* FIX: NOT YET IMPLEMENTED: Convert Unicode for accent and glyph to
   Unicode for the accented glyph. It's a table-lookup. *)
let get_uc_string_for_accented_character _acc_font _acc chr_font chr =
  GlyphText (UniText.of_ints (chr_font.get_unicode chr))
    (*?????????????????????????????????????????????????????????????????????????????????????????????????????????? *)

(*
  |attach_accent <acc-font> <acc> <chr-font> <chr>| attaches the character <acc> of <acc-font> to
  <chr> as accent.
*)
let attach_accent acc_font acc chr_font chr =
  let acc_gm = get_glyph_metric acc_font acc in
  let chr_gm = get_glyph_metric chr_font chr in
  let (pos_x, pos_y) = accent_position acc_font acc_gm chr_font chr_gm in
  let height = max_num chr_gm.gm_height (add_num acc_gm.gm_height pos_y) in
  let depth = max_num chr_gm.gm_depth (sub_num acc_gm.gm_depth pos_y) in
  let text = get_uc_string_for_accented_character acc_font acc chr_font chr in
    new_compound_box (fixed_dim chr_gm.gm_width) (fixed_dim height)
      (fixed_dim depth)
      [ Graphic.PutBox (dim_zero, dim_zero, new_glyph_box chr chr_font text);
        Graphic.PutBox (fixed_dim pos_x, fixed_dim pos_y,
                        new_glyph_box acc acc_font ClusterContinuation) ]
  
(*
  |vertical_extendable <height> <font> <top> <mid> <bot> <rep>| assembles an extendable glyph
  of the given height from <top>, <mid>, <bot>, and <rep>.
*)
let vertical_extendable height font top mid bot rep =
  let top_gm = get_glyph_metric font top in
  let mid_gm = get_glyph_metric font mid in
  let bot_gm = get_glyph_metric font bot in
  let rep_gm = get_glyph_metric font rep in
  let total_height gm = add_num gm.gm_height gm.gm_depth in
  let top_height = total_height top_gm in
  let mid_height = total_height mid_gm in
  let bot_height = total_height bot_gm in
  let rep_height = total_height rep_gm in
  let min_height = add_num (add_num top_height mid_height) bot_height in
  let num_reps =
    if rep_height = num_zero then
      0
    else
      begin
        let delta = sub_num height min_height in
        let num = int_of_num (ceiling_num (div_num delta rep_height)) in
          if mid = Undef then
            num
          else
            (num + 1) / 2
      end
  in
  let rep_list = XList.repeat num_reps (new_glyph_box rep font NoGlyphText) in
    VBox.make
      begin
        begin
          if top <> Undef then
            [ new_glyph_box top font NoGlyphText ]
          else
            []
        end @
          begin
            rep_list @
              begin              
                begin
                  if mid <> Undef then
                    (new_glyph_box mid font NoGlyphText) :: rep_list
                  else
                    []
                end @
                  begin
                    if bot <> Undef then
                      [ new_glyph_box bot font NoGlyphText ]
                    else
                      []
                  end
              end
          end
      end
  
(*
  |horizontal_extendable <width> <font> <left> <mid> <right> <rep>| assembles an extendable glyph
  of the given width from <left>, <mid>, <right>, and <rep>.
*)
let horizontal_extendable width font left mid right rep =
  let left_gm = get_glyph_metric font left in
  let mid_gm = get_glyph_metric font mid in
  let right_gm = get_glyph_metric font right in
  let rep_gm = get_glyph_metric font rep in
  let left_width = left_gm.gm_width in
  let mid_width = mid_gm.gm_width in
  let right_width = right_gm.gm_width in
  let rep_width = rep_gm.gm_width in
  let min_width = add_num (add_num left_width mid_width) right_width in
  let num_reps = if rep_width = num_zero then
    0
  else
    begin
      let delta = sub_num width min_width in
      let num = int_of_num (ceiling_num (div_num delta rep_width)) in
        if mid = Undef then
          num
        else
          (num + 1) / 2
    end
  in
  let rep_list = XList.repeat num_reps (new_glyph_box rep font NoGlyphText) in
    HBox.make HBox.LR
      begin
        begin
          if left <> Undef then
            [ new_glyph_box left font NoGlyphText ]
          else
            []
        end @
          begin
            rep_list @
              begin
                begin
                  if mid <> Undef then
                    [ new_glyph_box mid font NoGlyphText ]
                  else
                    []
                end @
                  begin                  
                    rep_list @
                      begin
                        if right <> Undef then
                          [ new_glyph_box right font NoGlyphText ]
                        else
                          []
                      end
                  end
              end
          end
      end
